﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Configuration;
using devtm.Helpers;
using devtm.Configuration;
using System.Reflection;
using System.ComponentModel;
using System.Windows;
using System.Globalization;
using devtm.Collections;
using devtm.Configuration.Models;
using devtm.Editor.Configuration.Templates;
using System.Text;
using System.Diagnostics;
using devtm.Config;

namespace devtm.Editor.Configuration.Data
{

    public abstract class ConfigProperty : IConfigProperty 
    {

        //public Urls Urls = new Urls();

        protected List<ConfigurationValidatorAttribute> _lstValidator = new List<ConfigurationValidatorAttribute>();
        public event PropertyChangedEventHandler PropertyChanged;
        private List<BoxSetting> _helpers = new List<BoxSetting>();
        protected CustomDesignerAttribute Editor;

        protected ConfigProperty()
        {
            Minimum = int.MinValue;
            Maximum = int.MaxValue;
        }

        #region ctor

        protected ConfigProperty(MemberInfo propertyinfo, ElementSection instance)
            : this()
        {

            
            MemberInfo = propertyinfo;
            Instance = instance;
            this.PropertyChanged += instance.ConfigProperty_PropertyChanged;
            
            if (propertyinfo is PropertyInfo)
            {
                PropertyInfo pp = (propertyinfo as PropertyInfo);

                SettingValue = BoxSetting.GetBoxSetting(pp, ConfigConstants.Design.Key).FirstOrDefault();

                _helpers = BoxSetting.GetBoxSetting(pp, ConfigConstants.Help.Key).ToList();

                Type = pp.PropertyType;
                _CanWrite = pp.CanWrite;

                SetValidator(pp);
                SetPropertie(pp);

                try
                {
                    // permet de tester la lecture
                    var test = Value;
                }
                catch (Exception)
                {
                    MessageBox.Show(string.Format(CultureInfo.CurrentCulture, devtm.Editor.Configuration.Properties.Resources.TheValueOf01CanTBeRead, pp.ReflectedType.Name, pp.Name));
                }
            }
        }


        private void SetValidator(PropertyInfo propertyinfo)
        {
            // recupere des parametres au cas ou l'on voudrait les avoir dans le WPF
            IntegerValidatorAttribute integerValidatorAttributeAtt = (Attribute.GetCustomAttributes(propertyinfo, typeof(IntegerValidatorAttribute)).FirstOrDefault() as IntegerValidatorAttribute);
            if (integerValidatorAttributeAtt != null)
            {
                Minimum = integerValidatorAttributeAtt.MinValue;
                Maximum = integerValidatorAttributeAtt.MaxValue;
            }

            StringValidatorAttribute stringValidatorAtt = (Attribute.GetCustomAttributes(propertyinfo, typeof(StringValidatorAttribute)).FirstOrDefault() as StringValidatorAttribute);
            if (stringValidatorAtt != null)
            {
                this.InvalidCharacters = stringValidatorAtt.InvalidCharacters;
                this.MaxLength = stringValidatorAtt.MaxLength;
                this.MinLength = stringValidatorAtt.MinLength;
                this.ValidatorType = stringValidatorAtt.ValidatorType;
            }
        }

        void SetPropertie(PropertyInfo propertyinfo)
        {

            Attribute[] attribu = Attribute.GetCustomAttributes(propertyinfo);

            if (attribu != null)
                foreach (Attribute a in attribu)
                    SetProperty(a);

            Type type = DictionaryTemplate.Get(propertyinfo.ReflectedType, Instance);
            if (type != null)
            {
                PropertyInfo prop1 = type.GetProperty(propertyinfo.Name);
                if (prop1 != null)
                {
                    Attribute[] Atts = Attribute.GetCustomAttributes(prop1);
                    foreach (Attribute item in Atts)
                        if (DictionaryTemplate.AttributIsForMe(Instance, item))
                            SetProperty(item);
                }
            }

        }

        private void SetProperty(Attribute a)
        {
            if (a.GetType().IsOfType(typeof(CustomDesignerAttribute)))
                _CanWrite = !_CanWrite || !(a as CustomDesignerAttribute).ReadOnly;

            if (a.GetType().IsOfType(typeof(devtm.Configuration.Models.CustomDesignerAttribute)))
            {

                CustomDesignerAttribute b = (CustomDesignerAttribute)a;

                if (!String.IsNullOrEmpty(b.PathName) 
                    && b.PathName != Instance.ParentItem.Path 
                    && b.PathName != Instance.Path)
                    return;

                if (a is CustomDesignerAttribute)
                {
                    if (Editor == null || String.IsNullOrEmpty((Editor as CustomDesignerAttribute).PathName))
                        Editor = (a as CustomDesignerAttribute);
                    
                }
                

            }
            else
            {
                if (a is ConfigurationValidatorAttribute)
                    _lstValidator.Add(a as ConfigurationValidatorAttribute);

                else if (a is DescriptionAttribute)
                    Description = (a as DescriptionAttribute).Description;

                else if (a is DisplayNameAttribute)
                    DisplayName = (a as DisplayNameAttribute).DisplayName;

            }
        }

        #endregion


        public IElementSection Instance { get; set; }
        public MemberInfo MemberInfo { get; set; }

        public virtual String PropertyName { get { return MemberInfo.Name; } set { } }

        public virtual String Name
        {
            get
            {
                return !String.IsNullOrEmpty(DisplayName) ? DisplayName : MemberInfo.Name;
            }
            set
            {

            }
        }

        [DebuggerNonUserCodeAttribute()]
        public virtual Object Value
        {
            get
            {
                try
                {
                    var i = (MemberInfo as PropertyInfo).GetValue(Instance.ConfigurationElement, null);
                    IsInError = false;
                    return i;
                }
                catch (Exception)
                {
                    IsInError = true;
                    //MessageBox.Show(Properties.Resources.ErrorOnSetValue, Properties.Resources.Error, MessageBoxButton.OK, MessageBoxImage.Error, MessageBoxResult.OK);

                    //(MemberInfo as PropertyInfo).SetValue(Instance.ConfigurationElement, String.Empty, null);
                    //MessageBox.Show(String.Format(CultureInfo.CurrentCulture, Properties.Resources.TheValueOf01HasBeenResetedBecauseNotValide
                    //    , Instance.ConfigurationElement.GetType().Name, MemberInfo.Name), Properties.Resources.Error, MessageBoxButton.OK, MessageBoxImage.Error, MessageBoxResult.OK);
                }
                return String.Empty;
            }
            set
            {

                Object oldValue = null;
                try
                {
                    oldValue = (MemberInfo as PropertyInfo).GetValue(Instance.ConfigurationElement, null);
                }
                catch (Exception)
                {
                    IsInError = true;
                }

                if (oldValue.Equals(value))
                    return;

                try
                {
                    Command.CommandHelpers.HasUpdated(Instance, Instance.ConfigurationElement, MemberInfo as PropertyInfo, oldValue, value);
                }
                catch (Exception)
                {
                    IsInError = true;
                    MessageBox.Show(devtm.Editor.Configuration.Properties.Resources.ErrorInTheCommandRecordMouvment, Properties.Resources.Error, MessageBoxButton.OK, MessageBoxImage.Error, MessageBoxResult.OK);
                }

                try
                {

                    (MemberInfo as PropertyInfo).SetValue(Instance.ConfigurationElement, value, null);

                    IsInError = false;
                }
                catch (Exception)
                {
                    IsInError = true;
                    MessageBox.Show(Properties.Resources.ErrorOnSetValue, Properties.Resources.Error, MessageBoxButton.OK, MessageBoxImage.Error, MessageBoxResult.OK);
                }

                try
                {
                    ValueHasChanged();
                }
                catch (Exception)
                {
                    MessageBox.Show(devtm.Editor.Configuration.Properties.Resources.ErrorOnEventChangeNotification, Properties.Resources.Error, MessageBoxButton.OK, MessageBoxImage.Error, MessageBoxResult.OK);
                }
                
            }
        }

        protected virtual void ValueHasChanged()
        {
            if (MemberInfo != null)
                MyPropertyChanged((MemberInfo as PropertyInfo).Name);
            MyPropertyChanged("ValueString");
            MyPropertyChanged("Value");

        }

        public virtual String ValueString
        {
            get
            {
                return Value != null ? Value.ToString() : String.Empty;
            }
        }
        public void MyPropertyChanged(String nameproperty)
        {
            if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(nameproperty));
        }

        #region IConfigProperty Members

        public abstract void RunEditor();

        public abstract void Selector();

        protected String DisplayName { get; set; }

        private string _Description;


        public string Description
        {
            get 
            {
                StringBuilder _s = new StringBuilder(_Description);
                foreach (ConfigurationValidatorAttribute v in _lstValidator)
                {
                    if (v is TimeSpanValidatorAttribute)
                    {
                        #region Timespan
                        
                        TimeSpanValidatorAttribute x = v as TimeSpanValidatorAttribute;
                        if (x.ExcludeRange)
                        
                            _s.AppendLine(String.Format(devtm.Editor.Configuration.Properties.Resources.DonTMustBeBetween0And1, x.MinValueString, x.MaxValueString));
                        else
                            _s.AppendLine(String.Format(devtm.Editor.Configuration.Properties.Resources.MustBeBetween0And1, x.MinValueString, x.MaxValueString));

                        #endregion

                    }
                    else if (v is StringValidatorAttribute)
                    {
                        #region string
                        
                        StringValidatorAttribute x1 = v as StringValidatorAttribute;
                        if (!string.IsNullOrEmpty(x1.InvalidCharacters))
                            _s.AppendLine(devtm.Editor.Configuration.Properties.Resources.DonTMustContains + x1.InvalidCharacters);
                        
                        if (x1.MinLength >0)
                            _s.AppendLine(String.Format(devtm.Editor.Configuration.Properties.Resources.DoitContenirAuMoinsCharactere ,
                                x1.MinLength,
                                x1.MinLength <= 1 ? String.Empty : "s"
                                ));

                        if (x1.MaxLength < 2147483647)
                            _s.AppendLine(String.Format(devtm.Editor.Configuration.Properties.Resources.PeutContenirJusquA0Charactere1 ,
                                x1.MaxLength,
                                x1.MinLength <= 1 ? String.Empty : "s"
                                ));

                        #endregion
                    }
                    else if (v is IntegerValidatorAttribute)
                    {
                        #region Integer
                        
                        IntegerValidatorAttribute x2 = v as IntegerValidatorAttribute;
                        if (x2.MinValue > 0 && x2.MaxValue < int.MaxValue)
                            _s.AppendLine(String.Format(devtm.Editor.Configuration.Properties.Resources.DoitetreComprisEntre0Et1,
                                x2.MinValue,
                                x2.MaxValue
                                ));

                        else if (x2.MinValue > 0 && x2.MaxValue == int.MaxValue)
                            _s.AppendLine(String.Format(devtm.Editor.Configuration.Properties.Resources.DoitetreSuperieura0,
                                x2.MinValue
                                ));

                        else if (x2.MinValue == 0 && x2.MaxValue != int.MaxValue)
                            _s.AppendLine(String.Format(devtm.Editor.Configuration.Properties.Resources.DoitetreInferieura0,
                                x2.MaxValue
                                ));

                        #endregion
                    }
                    else if (v is LongValidatorAttribute)
                    {
                        #region Long
                        
                        LongValidatorAttribute x3 = v as LongValidatorAttribute;

                        if (x3.MinValue > 0 && x3.MaxValue < long.MaxValue)
                            _s.AppendLine(String.Format(devtm.Editor.Configuration.Properties.Resources.DoitetreComprisEntre0Et1,
                                x3.MinValue,
                                x3.MaxValue
                                ));

                        else if (x3.MinValue > 0 && x3.MaxValue == long.MaxValue)
                            _s.AppendLine(String.Format(devtm.Editor.Configuration.Properties.Resources.DoitetreSuperieura0,
                                x3.MinValue
                                ));

                        else if (x3.MinValue == 0 && x3.MaxValue != long.MaxValue)
                            _s.AppendLine(String.Format(devtm.Editor.Configuration.Properties.Resources.DoitetreInferieura0,
                                x3.MaxValue
                                ));

                        #endregion
                    }
                    else if (v is RegexStringValidatorAttribute)
                    {
                        _s.AppendLine(devtm.Editor.Configuration.Properties.Resources.SoumisaLaValidationDUneExpressionReguliere);
                    }
                    else
                    {

                    }


                }

                return _s.ToString(); 
            }
            set { _Description = value; }
        }



        public Visibility ViewDescription { get { return String.IsNullOrEmpty(Description) ? Visibility.Hidden : Visibility.Visible; } }

        public int Minimum { get; set; }

        public int Maximum { get; set; }

        public Type Type { get; set; }

        public object Tag { get; set; }

        public string InvalidCharacters { get; set; }

        protected Type ValidatorType { get; set; }

        protected int MinLength { get; set; }

        protected int MaxLength { get; set; }

        //public event PropertyChangedEventHandler InError;


        private bool _isInError;
        public bool IsInError
        {
            get
            {
                return _isInError;
            }
            protected set
            {
                if (_isInError == value) return;
                _isInError = value;
                MyPropertyChanged("IsInError");
                MyPropertyChanged("VisibleError");

                MyPropertyChanged("VisibilityCanValidate");
                MyPropertyChanged("CanValidate");
            }
        }

        public bool CanValidate
        {
            get { return !_isInError; }
        }


        /// <summary>
        /// Tourne dans la liste des validators ajouté dans la config et les test un par un
        /// </summary>
        public virtual void Validator(Object o)
        {
            foreach (ConfigurationValidatorAttribute v in _lstValidator)
                try
                {
                    v.ValidatorInstance.Validate(o);

                }
                catch (Exception)
                {
                    IsInError = true;
                    return;
                }
            IsInError = false;
        }


        public Visibility VisibleError
        {
            get
            {
                if (IsInError)
                    return Visibility.Visible;

                return Visibility.Collapsed;
            }
        }

        public Visibility VisibilityCanValidate
        {
            get
            {
                if (!IsInError)
                    return Visibility.Visible;

                return Visibility.Collapsed;
            }
        }


        protected bool _CanWrite = true;
        public bool CanWrite
        {
            get { return _CanWrite; }
        }

        #endregion

        #region events

        public event EventHandler<EditorEventArgs> ConfigurationEventHandler;

        protected void ConfigurationEventHandlerEvent(object sender, IElementSection section)
        {
            if (ConfigurationEventHandler != null)
                ConfigurationEventHandler(sender, new EditorEventArgs(section));
        }

        #endregion

        public void RefreshForm()
        {
            MyPropertyChanged("Value");
        }

        protected BoxSetting SettingValue { get; set; }
        public IEnumerable<BoxSetting> Helpers { get { return _helpers; } }

    }

}
